package org.zjt.akka;
import akka.actor.AbstractActor;
import akka.actor.AbstractActor.Receive;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * Description:
 *
 * @author juntao.zhang
 * Date: 2018-06-26 下午8:10
 * @see
 */
@Slf4j
class PrintMyActorRefActor extends AbstractActor {

    @Override
    public void preStart() throws Exception {
        ActorRef secondRef = getContext().actorOf(Props.empty(), "second-actor");
        super.preStart();
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder().match(String.class, p -> log.info("Second: " + p)).build();
    }
}


@Slf4j
class StartStopActor1 extends AbstractActor {
    @Override
    public void preStart() {
        log.info("first started");
        getContext().actorOf(Props.create(StartStopActor2.class), "second");
    }

    @Override
    public void postStop() {
        log.info("first stopped");
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder().matchEquals("stop", s -> getContext().stop(getSelf())).build();
    }
}


@Slf4j
class StartStopActor2 extends AbstractActor {
    @Override
    public void preStart() {
        log.info("second started");
    }

    @Override
    public void postStop() {
        log.info("second stopped");
    }

    // Actor.emptyBehavior is a useful placeholder when we don't
    // want to handle any messages in the actor.
    @Override
    public Receive createReceive() {
        return receiveBuilder().build();
    }
}

@Slf4j
class StartStopActor3 extends AbstractActor {

    @Override
    public Receive createReceive() {
        return receiveBuilder().match(String.class,s -> log.info("接受到内容为:{}",s)).build();
    }
}


/**
 *
 * Actor来实现信息的流转和事件通知
 *
 *  等同于 事件 + Stream
 *
 */
@Slf4j
public class ActorHierarchyExperiments {

    ActorSystem system ;

    @Before
    public void startup() {
        system = ActorSystem.create("testSystem");
    }

    @Test
    public void method1() {
        ActorRef first = system.actorOf(Props.create(StartStopActor1.class), "first");
        first.tell("stop", ActorRef.noSender());
    }



    @Test
    public void method2() {
        ActorRef actorRef = system.actorOf(Props.create(StartStopActor3.class), "two");
        for (int i = 0; i < 1000; i++) {
            actorRef.tell("stop", ActorRef.noSender());
        }
    }





    @Test
    public void method4() {
        ActorRef firstRef = system.actorOf(Props.create(PrintMyActorRefActor.class), "first-actor");
        log.info("First: " + firstRef);
        for (int i = 0; i < 1000; i++) {
            firstRef.tell("printit", ActorRef.noSender());
        }
    }

    @After
    public void shutdown() throws InterruptedException {
        TimeUnit.SECONDS.sleep(20);
        system.terminate();
    }


}